package reader;


import java.io.BufferedReader;
import java.io.IOException;
import java.util.StringTokenizer;

import value_object.InstanceVO;
import value_object.data.End_Information;
import value_object.data.Request;
import value_object.data.Strip;

/**
 * <p> This class is responsible for reading an instance from an instance file
 * 
 * <p> The instance's information will be encapsulated by a InstanceVO object
 */

public class InstanceReader extends Reader {
	/**
	 * "Instances" directory
	 */
	private static final String FILE_DIRECTORY = "Instances";
	
	/**
	 * the instance file's name prefix
	 */
	private static final String FILE_NAME_PREFIX = "instance";
	
	public InstanceReader() {}	
	
	/**
	 * Overrides this method from the abstract one in the Reader superclass
	 * @return the instance file's directory
	 */
	@Override
	public String getFile_directory() { return FILE_DIRECTORY; }
	
	/**
	 * Overrides this method from the abstract one in the Reader superclass
	 * @return the prefix name of the instance file
	 */
	@Override
	public String getFile_name_prefix() { return FILE_NAME_PREFIX; }
	
	/**
	 * Read an instance from the instance file.
	 * @param x data set number
	 * @param y grid number
	 * @param z track number
	 * @return a InstanceVO object that contains the instance's information
	 * @throws IOException
	 */
	public InstanceVO readInstance(int x, int y, int z) throws IOException {	

		BufferedReader bfReader = getBufferedReader(x, y, z);		
		InstanceVO instance = new InstanceVO();

	    //Read File Line By Line
	    String strLine;
	    StringTokenizer tokenizer;
	    
	    // I. instance-information
	    strLine = bfReader.readLine();		    
	    tokenizer = new StringTokenizer(strLine, " ");
		instance.setData_set_number(Integer.parseInt(tokenizer.nextToken()));
		instance.setGrid_number(Integer.parseInt(tokenizer.nextToken()));
		instance.setTrack_number(Integer.parseInt(tokenizer.nextToken()));
    	
		// II. request-strip-numbers
		strLine = bfReader.readLine();
		tokenizer = new StringTokenizer(strLine, " ");
		int request_number = Integer.parseInt(tokenizer.nextToken());
		int strip_number = Integer.parseInt(tokenizer.nextToken());
	    
		// III. instance::solution-information
		bfReader.readLine(); //to-be-ignored x 3
		
		// IV. requests
		for (int i = 0; i < request_number; i++) {
			addARequestTo(instance, bfReader);
		}
		
		// V. strips
		for (int i = 0; i < strip_number; i++) {
			addAStripTo(instance, bfReader);
		}
		
	    //Close the buffered reader
		bfReader.close();
	     		
   		return instance;
	}
	
	/**
	 * Reads a request from the instance file, then adds it to an instance (object)
	 * @param instance InstanceVO object
	 * @param bfReader Buffered reader
	 * @throws IOException
	 */
	private void addARequestTo(InstanceVO instance, BufferedReader bfReader)
			throws IOException {		
		
		String strLine; strLine = bfReader.readLine();
		StringTokenizer tokenizer = new StringTokenizer(strLine, " ");
		
		Request request = new Request();
		request.setRequest_index(Integer.parseInt(tokenizer.nextToken()));
		request.setRequest_gain(Integer.parseInt(tokenizer.nextToken()));
		request.setRequest_surface(Float.parseFloat(tokenizer.nextToken()));
		request.setRequest_type(Integer.parseInt(tokenizer.nextToken()));
		request.setRequest_stereo(Integer.parseInt(tokenizer.nextToken()));	
		
		instance.addRequest(request);
	}
	
	/**
	 * Reads a strip from the instance file, then adds it to an instance (object)
	 * @param instance InstanceVO object
	 * @param bfReader Buffered reader
	 * @throws IOException
	 */
	private void addAStripTo(InstanceVO instance, BufferedReader bfReader)
			throws IOException {
		String strLine;
		StringTokenizer tokenizer;
		
		// 1. index-information
		strLine = bfReader.readLine();
		tokenizer = new StringTokenizer(strLine, " ");
		
		Strip strip = new Strip();
		strip.setStrip_index(Integer.parseInt(tokenizer.nextToken()));
		strip.setRequest_index(Integer.parseInt(tokenizer.nextToken()));
				tokenizer.nextToken(); //to-be-ignored
		strip.setTwin_strip_index(Integer.parseInt(tokenizer.nextToken()));
		//		tokenizer.nextToken(); //to-be-ignored
		
		// 2. selection-information
		strLine = bfReader.readLine(); //to-be-ignored x 2  		
		
		// 3. strip-information
		strLine = bfReader.readLine();
		tokenizer = new StringTokenizer(strLine, " ");
		
		strip.setStrip_surface(Float.parseFloat(tokenizer.nextToken()));
		strip.setStrip_acquisition_duration(Float.parseFloat(tokenizer.nextToken()));
		
		// 4. end0 & end1
		addEnd0End1To(strip, bfReader);
		
		instance.addStripToARequest(strip);
		instance.addStrip(strip);
	}

	/**
	 * Reads end0 and end1 from the instance file, then adds them to a strip (object)
	 * 
	 * @param strip Strip object
	 * @param bfReader Buffered reader
	 * @throws IOException
	 */
	private void addEnd0End1To(Strip strip, BufferedReader bfReader) throws IOException {
		String strLine;
		StringTokenizer tokenizer;
		
		for (int j = 0; j < 2; j++) {
			strLine = bfReader.readLine();
			tokenizer = new StringTokenizer(strLine, " ");
			
			End_Information end = new End_Information();
			end.setEnd_x_coordinate(Integer.parseInt(tokenizer.nextToken()));
			end.setEnd_y_coordinate(Integer.parseInt(tokenizer.nextToken()));
			end.setEnd_earliest_visibility(Float.parseFloat(tokenizer.nextToken()));
			end.setEnd_latest_visibility(Float.parseFloat(tokenizer.nextToken()));
			
			strip.setEnd(end, j); //j=0 => end0; j=1 => end1
		}
	}	
}
